;;########################################################################
;; hom-main.lsp
;; Copyright (c) 1995-2002 by Jan de Leeuw
;; Continuation of ViSta Plugin for Homogeneity Analysis.
;; Constructor function, defproto method, load statements and isnew method
;;########################################################################

; PLUGIN STEP 3: CONSTRUCTOR FUNCTION

;; The DATA and DIALOG keyword arguments of the constructor function
;; are required by all plugins, with the defaults used here.

;; The first three arguments of the call to isnew
;; must be as shown here. They must be used in the order shown.
;; The third one must be identical to the 
;; Following them are the homals arguments

(defun homogeneity-analysis
  (&key 
  (data *current-data*)     ; universal keyword
   (dialog nil)             ; universal keyword
   (p 3 p-used?)            ; computing dimensions 
   (dimensions 3 used?)     ; alias of p
   (iterations 100 itused?) ; alias of itmax
   (itmax 100 itmaxused?)   ; iterations
   (eps-0 0.0001)           ; number of decimals for function change (to convergence)
   (eps-1 0.0001)           ; number of decimals for solution change (to convergence)
   )
"Args: &key dimensions iterations eps-0 eps-1 data dialog
ViSta plugin to perform homogeneity analysis (also called multiple correspondance analysis) on n-way frequency data. Analysis is performed in a space with DIMENSIONS dimensionality. The analysis methods iterate for a maximum number of ITERATIONS, with EPS-0 and EPS-1 specifying values for the minimum change (epison) in convergence according to two different stopping rules (eps-0 is number of decimals for function change and eps-1 is number of decimals for solution change)."

  (when (and p-used? used? (/= p dimensions))
        (error "HOMALS: You cannot use both the p and the dimensions arguments."))
  
  (when (and itused? itmaxused? (/= iterations itmax))
        (error "HOMALS: You cannot use both the iterations and the itmax arguments."))
  
  (when used? (setf p dimensions))
  (when itused? (setf itmax iterations))

  (send homals-proto  :new "Homogeneity Analysis" data dialog p itmax eps-0 eps-1))
  

;; PLUGIN STEP 4: DEFPROTO STATEMENT

(defproto homals-proto  '(data-matrix n m z y d-m k-j-list row-ind-list col-ind-list dlist  p active-categories active-homals-variables sample-row-ind-list sample-col-ind-list weights weights-samp dlist-samp z-list variable-labels object-labels category-labels itmax category-labels output-file dialog  eps-0 eps-1 active-categories-category lab label-object-by data-object) () vista-analysis-plugin-object-proto )



;; PLUGIN STEP 5: CODE LOAD STATEMENTS
;; The additional files must be in a subdirectory and 
;; then loaded here with statemenst like:


  (load (strcat *homals-plugin-path* "homals-a"))
  (load (strcat *homals-plugin-path* "homals-b"))
  (load (strcat *homals-plugin-path* "homals-c"))
  (load (strcat *homals-plugin-path* "homals-d"))
  (load (strcat *homals-plugin-path* "homals-e"))
  (load (strcat *homals-plugin-path* "homals-f"))
  (load (strcat *homals-plugin-path* "core"))
  (load (strcat *homals-plugin-path* "cat-num"))
  (load (strcat *homals-plugin-path* "hom-report"))
  (load (strcat *homals-plugin-path* "hom-vis"))
  (load (strcat *homals-plugin-path* "hom-save"))


;; PLUGIN STEP 6: ISNEW METHOD

(defmeth homals-proto  :isnew (title data dialog p itmax eps-0 eps-1)
  ;(send self :data-object data)
  ;(send self :model-Abbrev "HMS")
  (send self :variable-labels (send data :active-variables '(category)))
  (send self :data-matrix (send self :change-matrix-to-numbers 
                                (send data :active-data-matrix '(category))))
  (send self :n (array-dimension (send self :data-matrix) 0))
  (send self :active-homals-variables (iseq (length (send self :variable-labels))))
  (send self :active-categories 
        (mapcar #'(lambda (var) 
                    (remove '99 (coerce 
                                 (remove-duplicates var :test #'=) 
                                 'list)))  
               	(column-list (send self :data-matrix))))
  (send self :category-labels
        (mapcar #'(lambda (var)       
                    (remove '"nil" (coerce 
                                    (remove-duplicates var :test #'equal) 
                                    'list) :test #'equal))
               	(column-list (send data :active-data-matrix '(category)))))
;rows with missing data are not considered
  (send self :object-labels 
        (select 
         (send data :active-labels)
        	(remove-duplicates 
          (combine 
           (mapcar #'(lambda (var) 
                       		(which (mapcar #'(lambda (el) (not (= 99 el))) 
                                        (coerce var 'list))))
                   (column-list (send self :data-matrix)))))))
  (send self :p p)
  (send self :itmax itmax)
  (send self :eps-0 eps-0)
  (send self :eps-1 eps-1)
  (call-next-method title data dialog)
  )